package com.algorithm.liyc.combine;

/**
 * 0037.解数独
 * 编写一个程序，通过填充空格来解决数独问题。
 * 一个数独的解法需遵循如下规则：
 * 数字 1-9 在每一行只能出现一次。
 * 数字 1-9 在每一列只能出现一次。
 * 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
 * 空白格用 '.' 表示。
 *
 * 提示：
 * ● 给定的数独序列只包含数字 1-9 和字符 '.' 。
 * ● 你可以假设给定的数独只有唯一解。
 * ● 给定数独永远是 9x9 形式的。
 *
 * 判断棋盘是否合法有如下三个维度：
 * ● 同行是否重复
 * ● 同列是否重复
 * ● 9宫格里是否重复
 * @author Liyc
 * @date 2024/1/24 17:16
 **/

public class Solution15 {

    public void solveSudoku(char[][] board) {
        findSudoku(board);
    }

    public boolean findSudoku(char[][] board) {
        //「一个for循环遍历棋盘的行，一个for循环遍历棋盘的列，
        // 一行一列确定下来之后，递归遍历这个位置放9个数字的可能性！」
        for (int i = 0; i < 9; i++) {// 遍历行
            for (int j = 0; j < 9; j++) {// 遍历列
                if (board[i][j] != '.') {// 跳过原始数字
                    continue;
                }
                for (char t = '1'; t <= '9'; t++) {// (i, j) 这个位置放t是否合适
                    if (isValidSudoku(i, j, t, board)) {
                        board[i][j] = t;
                        // 如果找到合适一组立刻返回
                        if (findSudoku(board)) return true;
                        board[i][j] = '.';
                    }
                }
                // 9个数都试完了，都不行，那么就返回false
                return false;
                // 因为如果一行一列确定下来了，这里尝试了9个数都不行，说明这个棋盘找不到解决数独问题的解！
                // 那么会直接返回， 「这也就是为什么没有终止条件也不会永远填不满棋盘而无限递归下去！」
            }
        }
        // 遍历完没有返回false，说明找到了合适棋盘位置了
        return true;
    }

    /**
     * * 判断棋盘是否合法有如下三个维度:
     *      *     同行是否重复
     *      *     同列是否重复
     *      *     9宫格里是否重复
     * @param row
     * @param col
     * @param val
     * @param board
     * @return
     */
    public boolean isValidSudoku(int row, int col, char val, char[][] board) {
        //同行是否重复
        for (int i = 0; i < 9; i++) {
            if (board[row][i] == val) return false;
        }

        //同列是否重复
        for (int i = 0; i < 9; i++) {
            if (board[i][col] == val) return false;
        }

        //9宫格里是否重复
        int startRow = (row / 3) * 3;
        int startCol = (col / 3) * 3;
        for (int i = startRow; i < startRow + 3; i++) {
            for (int j = startCol; j < startCol + 3; j++) {
                if (board[startRow][startCol] == val) return false;
            }
        }
        return true;
    }
}
